#include "opensles.h"
#include "string.h"
#include "iaudiodata.h"
#include <assert.h>
OpenSLES::OpenSLES()
{
    engineObject = 0;
    engineEngine = 0;

    outputMixObject = 0;
    outputMixEnvironmentalReverb = 0;

    bqPlayerObject = 0;
    bqPlayerPlay = 0;
    bqPlayerBufferQueue = 0;
    bqPlayerEffectSend = 0;
    bqPlayerMuteSolo = 0;
    bqPlayerVolume = 0;
    m_oIAudioData = 0 ;

    audioBuf = new char[4096];
}

OpenSLES::~OpenSLES()
{
    delete[] audioBuf;
}

void OpenSLES::Init(IAudioData *impl)
{
    m_oIAudioData = impl;
}

static const SLEnvironmentalReverbSettings reverbSettings =
    SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;

void OpenSLES::CreateEngine()
{
    SLresult result;

    // create engine
    result = slCreateEngine(&engineObject, 0, 0, 0, 0, 0);
    assert(SL_RESULT_SUCCESS == result);

    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);

    // get the engine interface, which is needed in order to create other objects
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    assert(SL_RESULT_SUCCESS == result);

    // create output mix, with environmental reverb specified as a non-required interface
    const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean req[1] = {SL_BOOLEAN_FALSE};
    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
    assert(SL_RESULT_SUCCESS == result);

    // realize the output mix
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);

    // get the environmental reverb interface
    // this could fail if the environmental reverb effect is not available,
    // either because the feature is not present, excessive CPU load, or
    // the required MODIFY_AUDIO_SETTINGS permission was not requested and granted
    result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
            &outputMixEnvironmentalReverb);
    if (SL_RESULT_SUCCESS == result) {
        result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
                outputMixEnvironmentalReverb, &reverbSettings);
    }
}

void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
    OpenSLES  * pthis = (OpenSLES  *)context;
    if(pthis)
        pthis->PlayerCallback(bq);
}

void OpenSLES::PlayerCallback(SLAndroidSimpleBufferQueueItf bq)
{
    assert(bq == bqPlayerBufferQueue);
    // for streaming playback, replace this test by logic to find and fill the next buffer
    memset(audioBuf,0,4096);
    if(m_oIAudioData)
        m_oIAudioData->GetAudio(audioBuf,4096);

    SLresult result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audioBuf, 4096);
    assert(SL_RESULT_SUCCESS == result);
}

void OpenSLES::CreateBufferQueueAudioPlayer(int rate, int channel,int bitsPerSample)
{
    SLresult result;

    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};

    SLDataFormat_PCM format_pcm;
    format_pcm.formatType = SL_DATAFORMAT_PCM;
    format_pcm.numChannels = channel;
    format_pcm.samplesPerSec = rate * 1000;
    format_pcm.bitsPerSample = bitsPerSample;
    format_pcm.containerSize = bitsPerSample;
    if(channel == 2)
        format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
    else
        format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;

    format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
    SLDataSource audioSrc = {&loc_bufq, &format_pcm};


  // configure audio sink
    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&loc_outmix, NULL};

    // create audio player
    const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND,
            /*SL_IID_MUTESOLO,*/ SL_IID_VOLUME};
    const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
            /*SL_BOOLEAN_TRUE,*/ SL_BOOLEAN_TRUE};
    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
            3, ids, req);
    assert(SL_RESULT_SUCCESS == result);
    (void)result;


    // realize the player
    result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);

    // get the play interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
    assert(SL_RESULT_SUCCESS == result);

    // get the buffer queue interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
            &bqPlayerBufferQueue);
    assert(SL_RESULT_SUCCESS == result);

    // register callback on the buffer queue
    result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this);
    assert(SL_RESULT_SUCCESS == result);

    // get the effect send interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,
            &bqPlayerEffectSend);
    assert(SL_RESULT_SUCCESS == result);

#if 0   // mute/solo is not supported for sources that are known to be mono, as this is
    // get the mute/solo interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);
    assert(SL_RESULT_SUCCESS == result);
#endif

    // get the volume interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
    assert(SL_RESULT_SUCCESS == result);
}

void OpenSLES::Start()
{
    SLresult result;

    result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
    assert(SL_RESULT_SUCCESS == result);

    memset(audioBuf,0,4096);
    if(m_oIAudioData)
        m_oIAudioData->GetAudio(audioBuf,4096);

    result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audioBuf, 4096);
    assert(SL_RESULT_SUCCESS == result);
}

void OpenSLES::Stop()
{
    SLresult result;

    result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
    assert(SL_RESULT_SUCCESS == result);
}

void OpenSLES::Destroy()
{
    if (bqPlayerObject != 0)
    {
         (*bqPlayerObject)->Destroy(bqPlayerObject);
         bqPlayerObject = 0;
         bqPlayerPlay = 0;
         bqPlayerBufferQueue = 0;
         bqPlayerEffectSend = 0;
         bqPlayerMuteSolo = 0;
         bqPlayerVolume = 0;
     }

    if (outputMixObject != 0) {
        (*outputMixObject)->Destroy(outputMixObject);
        outputMixObject = 0;
        outputMixEnvironmentalReverb = 0;
    }

    if (engineObject != 0) {
        (*engineObject)->Destroy(engineObject);
        engineObject = 0;
        engineEngine = 0;
    }
}


